package otSpaces.server.demo;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Properties;
import java.util.logging.Logger;

import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.AppListener;
import com.sun.sgs.app.Channel;
import com.sun.sgs.app.ChannelListener;
import com.sun.sgs.app.ChannelManager;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.ClientSessionListener;
import com.sun.sgs.app.Delivery;
import com.sun.sgs.app.ManagedObject;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.PeriodicTaskHandle;
import com.sun.sgs.app.Task;

public class DemoSender implements AppListener, Serializable {

	/**
	 * This listener just logs the number of bytes in each packet
	 */
	public static class LoggingChannelListener implements ChannelListener,
			Serializable {

		public static final Logger LOG = Logger
				.getLogger(LoggingChannelListener.class.getName());

		private static final long serialVersionUID = 1L;

		@Override
		public void receivedMessage(Channel channel, ClientSession sender,
				ByteBuffer message) {
			LOG.info("Channel [" + channel.getName() + "] recieved "
					+ message.remaining() + " bytes of data from ("
					+ sender.getName() + ")");
		}
	}

	/**
	 * This listener just logs the number of bytes in each packet
	 */
	public static class LoggingClientSessionListener implements
			ClientSessionListener, Serializable {

		public static final Logger LOG = Logger
				.getLogger(LoggingClientSessionListener.class.getName());

		private static final long serialVersionUID = 1L;

		public LoggingClientSessionListener() {
		}

		@Override
		public void disconnected(boolean graceful) {
			LOG.info("Was disconnected " + (graceful ? "" : "un")
					+ "gracefully");
		}

		@Override
		public void receivedMessage(ByteBuffer message) {
			LOG.info("Called with " + message.remaining() + " bytes of data");
		}
	}

	/**
	 * This {@link Task} just sends the system time
	 */
	public static class SystemCurrentTimeTask implements ManagedObject,
			Serializable, Task {

		public static final Logger LOG = Logger
				.getLogger(SystemCurrentTimeTask.class.getName());

		private static final long serialVersionUID = 1L;

		public static ByteBuffer currentTimeMillis() {

			final ByteBuffer data = ByteBuffer.allocate(Long.SIZE / 8);

			data.putLong(System.currentTimeMillis()).flip();

			return data;
		}

		public final ManagedReference<Channel> _channelRef;
		public final long _period;

		public final PeriodicTaskHandle _periodicTaskHandle;

		public SystemCurrentTimeTask(Channel channel, long period) {

			AppContext.getDataManager().createReference(this);

			_period = period;

			_channelRef = AppContext.getDataManager().createReference(channel);

			_periodicTaskHandle = AppContext.getTaskManager()
					.schedulePeriodicTask(this, period, period);
		}

		@Override
		public void run() throws Exception {

			_channelRef.get();

			_channelRef.get().send(currentTimeMillis());
		}
	}

	private static final long serialVersionUID = 1L;

	@Override
	public void initialize(Properties props) {

		// locate the topic space named "System."
		// the name can be whatever you want, and the things are created
		// on-demand
		// These should be Serializable if you really have to. I'd really prefer
		// that you just refereed to them by name
		final ChannelManager channelManager = otSpaces.server.OtSpacesRegistry
				.locate("System");

		// create a channel (as usual - but it must be null or RELIABLE
		// delivery)
		final Channel channel = channelManager.createChannel(
				"currentTimeMillis", new LoggingChannelListener(),
				Delivery.RELIABLE);

		// this just sets up a task that sends the system time to the channel as
		// a long
		new SystemCurrentTimeTask(channel, 500);
	}

	@Override
	public ClientSessionListener loggedIn(ClientSession session) {

		// again as above
		final ChannelManager channelManager = otSpaces.server.OtSpacesRegistry
				.locate("System");

		// just locate the named channel. it'll return null if it doen't exist
		final Channel channel = channelManager.getChannel("currentTimeMillis");

		// see what I meant about "Nothing is different"
		channel.join(session);

		//
		return new LoggingClientSessionListener();
	}
}
